﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Design;
using System.Windows.Forms.Design;

namespace Tools {
	public partial class wndAssetSelector : Form {
		public Image SelectedAsset { get; set; }
		public string Value { get; set; }

		// ----------

		public wndAssetSelector() {
			InitializeComponent();
			
			Globals.SetDoubleBuffered( splitContainer1.Panel2 );
			Globals.SetDoubleBuffered( pbCanvas );

			// ----------

			TreeNode root = new TreeNode( "Assets" );
			AddTopDirectories( root, Globals.AssetsPath );
			tvAssets.Nodes.Add( root );

			root.Expand();
		}

		// ----------
		// Hooks

		private void tvAssets_AfterSelect( object sender, TreeViewEventArgs e ) {
			try {
				Image img = Image.FromFile( (string)e.Node.Tag );
				SelectedAsset = img;
				Value = ((string)e.Node.Tag).Remove( 0, Globals.AssetsPath.Length );
				Value = Value.Replace( Path.GetExtension(Value), "" );
				pbCanvas.Refresh();
			} catch {}
		}

		private void tvAssets_NodeMouseDoubleClick( object sender, TreeNodeMouseClickEventArgs e ) {
			// Just to make sure
			try {
				Image img = Image.FromFile( (string)e.Node.Tag );
				SelectedAsset = img;
				Value = ((string)e.Node.Tag).Remove( 0, Globals.AssetsPath.Length );
				Value = Value.Replace( Path.GetExtension(Value), "" );
				pbCanvas.Refresh();
			} catch {}
			
			DialogResult = System.Windows.Forms.DialogResult.OK;
			Close();
		}

		private void pbCanvas_Paint( object sender, PaintEventArgs e ) {
			// Graphics settings
			e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
			e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half;

			if( SelectedAsset != null ) {
				int cw = pbCanvas.Width;
				int ch = pbCanvas.Height;
				int aw = SelectedAsset.Width;
				int ah = SelectedAsset.Height;
				int x = cw/2-aw/2;
				int y = ch/2-ah/2;

				// Draw Asset
				e.Graphics.DrawImage( SelectedAsset, x, y, aw, ah );

				// Asset Outline
				Pen p = new Pen( Color.FromArgb(200,255,100,100) );
				p.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
				
				e.Graphics.DrawLine( p, x, y, x+aw+1, y );
				e.Graphics.DrawLine( p, x+aw+1, y, x+aw+1, y+ah+1 );
				e.Graphics.DrawLine( p, x, y+ah+1, x+aw+1, y+ah+1 );
				e.Graphics.DrawLine( p, x, y, x, y+ah+1 );
			}
		}

		private void cmdSelect_Click( object sender, EventArgs e ) {
			DialogResult = System.Windows.Forms.DialogResult.OK;
			Close();
		}

		// ----------
		// http://stackoverflow.com/questions/2135851/treeview-control-contextswitchdeadlock-workarounds

		private void tvAssets_BeforeExpand( object sender, TreeViewCancelEventArgs e ) {
		   if( e.Node.Tag != null ) {
			   AddTopDirectories( e.Node, (string)e.Node.Tag );
		   }
		}

		private void AddTopDirectories( TreeNode node, string path ) {
			tvAssets.BeginUpdate(); // for best performance
			node.Nodes.Clear(); // clear dummy node if exists

			try {
				DirectoryInfo info = new DirectoryInfo( path );
				if( !info.Exists )
					return;
				
				// Sort available directories
				DirectoryInfo[] subdirs = info.GetDirectories();
				Array.Sort(
					subdirs,
					delegate( DirectoryInfo a, DirectoryInfo b ) {
						return a.Name.CompareTo( b.Name );
					}
				);

				// Sort available files
				FileInfo[] files = info.GetFiles();
				Array.Sort(
					files,
					delegate( FileInfo a, FileInfo b ) {
						return a.Name.ToLower().CompareTo( b.Name.ToLower() );
					}
				);

				// Add directries
				foreach( DirectoryInfo subdir in subdirs ) {
					TreeNode child = new TreeNode( subdir.Name );
					child.Tag = subdir.FullName;
					child.ImageIndex = 0;
					child.SelectedImageIndex = 0;

					// if have subdirs, add dummy node
					// to display the [+] allowing expansion
					if( subdir.GetFileSystemInfos().Length > 0 ) {
						child.Nodes.Add( new TreeNode() ); 
					}

					node.Nodes.Add( child );
				}

				// Add files
				foreach( FileInfo file in files ) {
					TreeNode child = new TreeNode( file.Name );
					child.Tag = file.FullName;

					int i;
					if( !Globals.Extensions.TryGetValue(file.Extension,out i) )
						i = 1;

					child.ImageIndex = i;
					child.SelectedImageIndex = i;

					node.Nodes.Add( child );
				}
			} catch( UnauthorizedAccessException ) {
				// ignore dir
			} finally {
				tvAssets.EndUpdate(); // need to be called because we called BeginUpdate
				node.Tag = null; // clear tag
			}
		}
	}

	// ----------

	public class AssetSelectorEditor : UITypeEditor {
		public override UITypeEditorEditStyle GetEditStyle( ITypeDescriptorContext context ) {
			return UITypeEditorEditStyle.Modal;
		}

		public override object EditValue( ITypeDescriptorContext context, IServiceProvider provider, object value ) {
			IWindowsFormsEditorService svc = provider.GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService;

			if( svc != null ) {
				using( wndAssetSelector form = new wndAssetSelector() ) {
					if( svc.ShowDialog(form) == DialogResult.OK ) {

						AssetPathHandler handler = null;
						foreach(Attribute attr in context.PropertyDescriptor.Attributes) {
							if( attr is AssetPathHandlerAttribute ) {
								handler = (AssetPathHandler)Activator.CreateInstance( ((AssetPathHandlerAttribute)attr).HandlerType );
								break;
							}
						}

						if( handler != null )
							form.Value = handler.SanitizeAssetPath( form.Value );

						value = form.Value;

					}
				}
			}

			return value;
		}
	}
}
